﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace MyChart
{
    /// <summary>
    /// 多维数据源包装类。有多个值列的数据源。由于FusionCharts的数据结构是一维的（一个值列），
    /// 所以需要为多维数据源包装成符合FusionCharts数据结构要求的数据源。
    /// </summary>
    public class MultiDimensionalDataSource
    {
        #region 字段

        private readonly string _autoSeriesFieldName = "__DataSeriesField";
        private readonly string _autoValueFieldName = "__DataValueField";
        private readonly string _autoTextFieldName = "__DataTextField";

        private DimensionDictionary _dimensionConfigs = new DimensionDictionary();
        private string _dataSeriesField;
        private string _dataTextField;

        private DataView _dataSource;
        private string _dataSourceRowFilter = "";

        #endregion

        #region 属性

        /// <summary>
        /// 获取数据格式转换后自动生成的序列字段名
        /// </summary>
        public string AutoSeriesFieldName
        {
            get { return _autoSeriesFieldName; }
        }

        /// <summary>
        /// 获取数据格式转换后自动生成的值字段名
        /// </summary>
        public string AutoValueFieldName
        {
            get { return _autoValueFieldName; }
        }

        /// <summary>
        /// 获取数据格式转换后自动生成的文本字段名
        /// </summary>
        public string AutoTextFieldName
        {
            get { return _autoTextFieldName; }
        }

        /// <summary>
        /// 获取或设置维度配置字典
        /// </summary>
        public DimensionDictionary DimensionConfigs
        {
            get { return _dimensionConfigs; }
            set { _dimensionConfigs = value; }
        }

        /// <summary>
        /// 获取或设置序列字段名
        /// </summary>
        public string DataSeriesField
        {
            get { return _dataSeriesField; }
            set { _dataSeriesField = value; }
        }

        /// <summary>
        /// 获取或设置文本字段名
        /// </summary>
        public string DataTextField
        {
            get { return _dataTextField; }
            set { _dataTextField = value; }
        }

        #endregion

        #region 构造器

        /// <summary>
        /// 初始化 MultiDimensionalDataSource  类
        /// </summary>
        /// <param name="dataSource">原是多维数据源</param>
        public MultiDimensionalDataSource(object dataSource)
        {
            DataView view;
            if (dataSource is DataSet)
            {
                view = (dataSource as DataSet).Tables[0].DefaultView;
            }
            else if (dataSource is DataTable)
            {
                view = (dataSource as DataTable).DefaultView;
            }
            else if (dataSource is DataView)
            {
                view = dataSource as DataView;
            }
            else
            {
                throw (new Exception("DataSource不是有效的数据源！"));
            }
            _dataSource = view;
            _dataSourceRowFilter = view.RowFilter;
        }

        #endregion

        #region 方法

        /// <summary>
        /// 获取转换成FusionChart所要求格式的数据源
        /// </summary>
        /// <returns>FusionChart所要求格式的数据源</returns>
        public DataView GetDataSource()
        {
            //基本思想：把原数据源转换后的数据源放到新的DataTable中，再返回这个新的DataTable
            //转换算法：对数据源的序列字段、文本字段、维度字段的数据做笛卡尔乘积运算
            //把运算结果的3个字段的数据加上对应的原数据源中的行，组成一条新的数据行加入到新的DataTable中

            //如果没有序列字段则只对文本字段、维度字段的数据做笛卡尔乘积运算（文本字段、维度字段是必须的，序列字段是可选的）
            
            DataTable table = new DataTable();

            foreach (DataColumn col in _dataSource.Table.Columns)
            {
                DataColumn c = new DataColumn(col.ColumnName);
                table.Columns.Add(c);
            }
            table.Columns.Add(_autoSeriesFieldName);
            table.Columns.Add(_autoTextFieldName);
            table.Columns.Add(_autoValueFieldName);

            List<string> texts = new List<string>();
            foreach (DataRowView drv in _dataSource)
            {
                string text = drv[_dataTextField].ToString();
                if (!texts.Contains(text))
                {
                    texts.Add(text);
                }
            }

            List<string> series = new List<string>();
            if (!string.IsNullOrEmpty(_dataSeriesField))
            {
                foreach (DataRowView drv in _dataSource)
                {
                    string seriesName = drv[_dataSeriesField].ToString();
                    if (!series.Contains(seriesName))
                    {
                        series.Add(seriesName);
                    }
                }
            }

            if (series.Count > 0)
            {
                foreach (string dimension in _dimensionConfigs.Keys)
                {
                    foreach (string seriesName in series)
                    {
                        foreach (string text in texts)
                        {
                            _dataSource.RowFilter = _dataTextField + "='" + text + "' AND " + _dataSeriesField + "='" + seriesName + "'";
                            if (_dataSource.Count == 0)
                            {
                                continue;
                            }
                            DataRow row = table.NewRow();
                            foreach (DataColumn col in _dataSource.Table.Columns)
                            {
                                row[col.ColumnName] = _dataSource[0][col.ColumnName];
                            }
                            row[_autoSeriesFieldName] = _dimensionConfigs[dimension].Text + "(" + _dataSource[0][_dataSeriesField] + ")";
                            row[_autoTextFieldName] = _dataSource[0][_dataTextField];
                            row[_autoValueFieldName] = _dataSource[0][dimension];
                            table.Rows.Add(row);
                        }
                    }
                }
            }
            else
            {
                foreach (string text in texts)
                {
                    _dataSource.RowFilter = _dataTextField + "='" + text + "'";
                    foreach (string dimension in _dimensionConfigs.Keys)
                    {
                        DataRow row = table.NewRow();
                        foreach (DataColumn col in _dataSource.Table.Columns)
                        {
                            row[col.ColumnName] = _dataSource[0][col.ColumnName];
                        }
                        row[_autoSeriesFieldName] = _dimensionConfigs[dimension].Text;
                        row[_autoTextFieldName] = _dataSource[0][_dataTextField];
                        row[_autoValueFieldName] = _dataSource[0][dimension];
                        table.Rows.Add(row);
                    }
                }
            }
            _dataSource.RowFilter = _dataSourceRowFilter;

            return table.DefaultView;
        }

        /// <summary>
        /// 获取转换数据源后的序列配置字典。用来配置控件的相关序列呈现属性。
        /// </summary>
        /// <returns>转换数据源后的序列配置字典</returns>
        public Dictionary<string, SeriesConfig> GetSeriesConfigs()
        {
            //基本思想：所谓维度，就是多个序列的集合。
            //获取转换数据源后的序列配置字典，也就是通过维度配置生成对应的多个序列的配置对象，并通过序列名组成字典。
            Dictionary<string, SeriesConfig> seriesConfigs = new Dictionary<string, SeriesConfig>();

            List<string> series = new List<string>();
            if (!string.IsNullOrEmpty(_dataSeriesField))
            {
                foreach (DataRowView drv in _dataSource)
                {
                    string seriesName = drv[_dataSeriesField].ToString();
                    if (!series.Contains(seriesName))
                    {
                        series.Add(seriesName);
                    }
                }

                foreach (string seriesName in series)
                {
                    foreach (string dimension in _dimensionConfigs.Keys)
                    {
                        if (_dimensionConfigs.ContainsKey(dimension))
                        {
                            SeriesConfig sc = new SeriesConfig();
                            seriesConfigs[_dimensionConfigs[dimension].Text + "(" + seriesName + ")"] = _dimensionConfigs[dimension];
                        }
                    }
                }
            }
            else
            {
                foreach (string dimension in _dimensionConfigs.Keys)
                {
                    if (_dimensionConfigs.ContainsKey(dimension))
                    {
                        SeriesConfig sc = new SeriesConfig();
                        seriesConfigs[_dimensionConfigs[dimension].Text] = _dimensionConfigs[dimension];
                    }
                }
            }

            return seriesConfigs;
        }

        #endregion
    }
}
